/**
 * 2017年10月13日
 */
package exp.algorithm.sic;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import exp.algorithm.sic.feature.FeatureVector;

/**
 * 用来对一个TimeSeries进行ScalePeak提取,最终的结果以{@link InstanceFeatureVectors}表示
 * {@link InstanceFeatureVectors}中保存了该实例的类标,该实例每个Octave中的特征点,及特点点的特征值
 * 特征值具体是什么由具体方法决定
 * @author Alex
 *
 */
public class Sifc {
	Logger log = LoggerFactory.getLogger(Sifc.class);
	//PythonPlotWriter ppw = ExpDriver.context.getBean(PythonPlotWriter.class);
    // 以下常数均是论文中推荐的参数值
    float preprocSigma             = 1.5f;   // 用于处理被double后的图像预处理的模糊因子
    float octaveSigma              = 1.6f;   // 用于处理每个8度空间图像的模糊因子
    int    minimumRequiredPixelsize = 32;    // 高斯金字塔中缩小时最小的尺寸
    int    scaleSpaceLevels         = 3;     // 每个8度空间需要获取极值点的差分图层，加上用于比较的上下层至少要有5个差分图像，所以至少要有6个高斯模糊图象。
    float dogThresh                = 0.0075f; // 在差分图象上的极致点值最小值，防止大片的模糊后的点被选中，这个值越小选中的点越多。
    float dValueLowThresh          = 0.008f; // 和周围点比较的差值，这个差值是经过导数运算的差值，不是直接比较的。论文中建议为0.03（page
                                              // 11），但获取的点数太少，这里修改为0.008
    float maximumEdgeRatio         = 20.0f;  // 非角点的过虑比
    float scaleAdjustThresh        = 0.50f;  // 尺度空间的精确点和真实图象上的离散点在投谢时需要调整，这个是最大调整范围，超这个值就可能是下一个点。
    float peakRelThresh            = 0.8f;   //
    int    relocationMaximum        = 4;
    
    PeakFinderType pf;
    VectorMakerType vm;
    
	public Sifc() {
		this(PeakFinderType.DENSE,VectorMakerType.STATSHAPE);
	}
    
	public Sifc(PeakFinderType pft,VectorMakerType vmt) {
		pf = pft;
		vm = vmt;
	}
	
	
    public  List<FeatureVector> detectFeatures(TimeSeries ts) {
        return (detectFeaturesDownscaled(ts, -1, 1.0f));
    }
    /**
     * @param img
     * @param preProcessMark 图象预处理的标记，小于0，img需要double,大于0时，说明图象的长和宽要half到这个尺寸以下，等于0则不预处理
     * @param startScale
     * @return
     */
    public List<FeatureVector> detectFeaturesDownscaled(TimeSeries img, int preProcessMark, float startScale) {
       
        if (preprocSigma > 0.0) {
            GaussianArray gaussianPre = new GaussianArray(preprocSigma);
            img = gaussianPre.convolve(img);
        }
        Pyramid pyr = new Pyramid(pf,vm);
        pyr.buildOctaves(img, startScale, scaleSpaceLevels, octaveSigma, minimumRequiredPixelsize);

        ArrayList<FeatureVector> fvs = new ArrayList<>();
        for (int on = 0; on < pyr.octaves.size(); ++on) {
            OctaveSpace osp = pyr.octaves.get(on);
            //寻找序列中的极值点
            List<ScalePeak> peaks = osp.findPeaks(dogThresh);
            //构造特征点的描述子
            fvs.addAll(osp.createFeatureDescriptor(peaks));
        }
        return fvs;
    }
}
